﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Reflection;
using System.Diagnostics;
using System.Web;
using System.IO;

namespace SharpMedia
{
    /// <summary>
    /// Handles unhandled exceptions by flushing a stacktrace to an error file and provide the option of sending it to the developer of SharpMedia
    /// </summary>
    public static class ErrorHandling
    {
        private static string DeveloperMail = "felizk@gmail.com";
        private static string errorLogFile;
        public static event EventHandler Error;
        public static string StackTrace;
        public static Exception Exception;
        /// <summary>
        /// Initializes Error Handling. Hooks Application.ThreadException and AppDomain.CurrentDomain.UnhandledException.
        /// </summary>
        /// <param name="logFile">The log file to which a stacktrace is written upon unhandled exception.</param>
        public static void Initialize(string logFile)
        {
            ErrorHandling.errorLogFile = logFile;
            AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
        }

        /// <summary>
        /// Removes eventhandles added to Application and AppDomain.CurrentDomain
        /// </summary>
        public static void Unload()
        {
            AppDomain.CurrentDomain.UnhandledException -= CurrentDomain_UnhandledException;
        }

        static void Application_ThreadException(object sender, ThreadExceptionEventArgs e)
        {
            // If it is an Invocation Exception, we're really only interested in what caused the inner exception
            // Not that it was caused by Sharpmedia.RunInUpdate as it is 99% of the time :)
            bool isInvocationException = e.Exception.GetType() == typeof(TargetInvocationException);

            string s = GetExceptionLogEntry(isInvocationException ? e.Exception.InnerException : e.Exception, 0);
            
            string prevLog = File.Exists(errorLogFile) ? File.ReadAllText(errorLogFile) : "";
            
            File.WriteAllText(errorLogFile, s + Environment.NewLine + prevLog);
            
            // Drop out of fullscreen as it occludes the messagebox.
//            SharpMedia.Form.WindowState = FormWindowState.Minimized;
            
            // In case the debugger is attached, we want it to handle the exception.
            if (!Debugger.IsAttached)
            {
                // The extra thread is needed. Because the Message Pump is blocked and not receiving Windows Messages (mouse clicks)
//                Thread t = new Thread(new ParameterizedThreadStart(ShowMessage));
//                t.IsBackground = false;
//                t.Start(new object[] { e, s });
                System.Environment.Exit(1);
            }
            else
            {
                throw e.Exception;
            }

        }

        static string GetExceptionLogEntry(Exception e, int indent)
        {
            string pad = "";
            for (int i = 0; i < indent; i++)
            {
                pad += "  ";
            }

            StringBuilder sb = new StringBuilder();
            sb.AppendFormat(pad + "-------------------------------------- {0} ---------------------------------", e.GetType().ToString());
            sb.AppendLine();
            sb.AppendFormat(pad + "Time: {0}", DateTime.Now.ToShortDateString() + " " + DateTime.Now.ToLongTimeString());
            sb.AppendLine();
            sb.AppendFormat(pad + "Message: {0}", e.Message);
            sb.AppendLine();
            sb.AppendFormat(pad + "Stacktrace:");
            sb.AppendLine();
            if (e.StackTrace != null)
                foreach (var line in e.StackTrace.Split(new string[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries))
                {
                    sb.AppendLine(pad + line);
                }

            if (e.InnerException != null)
                sb.AppendLine(GetExceptionLogEntry(e.InnerException, indent + 1));

            return sb.ToString();
        }


        static void ShowMessage(object o)
        {
            /*object[] objs = (object[])o;
            ThreadExceptionEventArgs e = (ThreadExceptionEventArgs)objs[0];
            string sb = (string)objs[1];
            if (MessageBox.Show("Sorry the program crashed! Message: " + e.Exception.Message + Environment.NewLine + "Want to send a mail to the developer?", "Crash!", MessageBoxButtons.YesNo, MessageBoxIcon.Error) == DialogResult.Yes)
            {
                Process.Start("mailto:"+DeveloperMail+"?subject=%5BSharpMedia%5D%20" + HttpUtility.UrlPathEncode(e.Exception.Message) + "&body=" + HttpUtility.UrlPathEncode(sb.ToString()));
            }
            // Wait for the message box to disappear and then exit the program.
            System.Environment.Exit(1);*/
        }

        static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
        {
            Application_ThreadException(sender, new ThreadExceptionEventArgs((Exception)e.ExceptionObject));
        }
        
    }
}
